package com.huantai.common.util;

import java.math.BigDecimal;

import com.huantai.common.exception.BusinessException;
import com.huantai.common.exception.SystemException;

/**
 * BigDecimal 工具类
 * 
 * @author Ma Chao
 * @version 2018年4月3日 下午2:19:13
 */
public final class BigDecimalUtil {
    /** 不允许使用对象来调用工具类的方法 */
    private BigDecimalUtil() {}

    /** 除法运算默认精度 */
    private static final int DEFAULT_SCALE = 6;

    /**
     * 加法
     * 
     * @param a 加数
     * @param b 被加数
     * @return a+b
     */
    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return b;
        }
        if (null == b) {
            return a;
        }
        return a.add(b);
    }

    /**
     * 减法
     * 
     * @param a 被减数
     * @param b 减数
     * @return a-b
     */
    public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return BigDecimal.ZERO.subtract(b);
        }
        if (null == b) {
            return a;
        }
        return a.subtract(b);
    }

    /**
     * 乘法，小数位数取两者间大的
     * 
     * @param a 被乘数
     * @param b 乘数
     * @return a*b
     */
    public static BigDecimal multiply(BigDecimal a, BigDecimal b) {
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return BigDecimal.ZERO;
        }
        if (null == b) {
            return BigDecimal.ZERO;
        }
        int scaleA = a.scale();
        int scaleB = b.scale();
        int scale = scaleA > scaleB ? scaleA : scaleB;
        return round(a.multiply(b), scale);
    }

    /**
     * 乘法，保留scale位小数
     * 
     * @param a 被乘数
     * @param b 乘数
     * @param scale 保留小数位数
     * @return a*b
     */
    public static BigDecimal multiply(BigDecimal a, BigDecimal b, int scale) {
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return BigDecimal.ZERO;
        }
        if (null == b) {
            return BigDecimal.ZERO;
        }
        return round(a.multiply(b), scale);
    }

    /**
     * 除法，根据默认精度进行四舍五入运算
     * 
     * @param a 除数
     * @param b 被除数
     * @return a/b
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b) {
        return divide(a, b, DEFAULT_SCALE);
    }

    /**
     * 除法，根据传入精度进行四舍五入运算
     * 
     * @Title: divide
     * @param a 除数
     * @param b 被除数
     * @param scale 精度
     * @return 结果
     * @throws BusinessException
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int scale) {
        if (0 > scale) {
            throw new SystemException("小数位数不能小于零！"); // NOSONAR
        }
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return BigDecimal.ZERO;
        }
        if (null == b || BigDecimal.ZERO.equals(b)) {
            throw new SystemException("小数位数不能小于零！");
        }
        return a.divide(b, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 除法，根据传入精度和进位方式进行运算
     * 
     * @Title: divide
     * @param a 除数
     * @param b 被除数
     * @param scale 精度
     * @param roundModel 小数进位模式
     * @return 结果
     * @throws BusinessException
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int scale, int roundModel) {
        if (0 > scale) {
            throw new SystemException("小数位数不能小于零！");
        }
        if (null == a && null == b) {
            return null;
        }
        if (null == a) {
            return BigDecimal.ZERO;
        }
        if (null == b || BigDecimal.ZERO.equals(b)) {
            throw new SystemException("不能除以零！");
        }
        return a.divide(b, scale, roundModel);
    }

    /**
     * 四舍五入，保留scale位小数
     * 
     * @param v 要处理的数据
     * @param scale 小数位数
     * @return 处理完毕的数据
     * @throws BusinessException
     */
    public static BigDecimal round(BigDecimal v, int scale) {
        if (0 > scale) {
            throw new SystemException("小数位数不能小于零！");
        }
        if (null == v) {
            return null;
        }
        return divide(v, new BigDecimal("1"), scale);
    }
}
